<?php

class Model{

    // 定义查询所需要的参数
    protected $wheres;
    protected $limit;
    protected $columns;

    // 获取表名,如果没有定义，将类名转换为复数形式后，在转换为「蛇式」命名，设置表名
    // 例如 UserMobile 会转变为 users
    public function getTable()
    {
        if (! isset($this->table)) {
            return str_replace(
                '\\', '', \Illuminate\Support\Str::snake(\Illuminate\Support\Str::plural(class_basename($this)))
            );
        }

        return $this->table;
    }

    // 根据上面的一些条件拼装sql;
    public function toSql()
    {
        // 这里实现步骤大家可以自己去拼写
        $sql = '';

        return $sql;
    }

    public function get($columns = ['*'])
    {
        $this->columns = $columns;

        // 执行mysql语句
        $results = mysql_query($this->toSql());

        return $results;
    }

    // 设置参数
    public function take($value)
    {
        return $this->limit = $value;
    }

    public function first($columns)
    {
        return $this->take(1)->get($columns);
    }

    public function where($column, $operator = null, $value = null)
    {
        $this->wheres[] = compact(
            'type', 'column', 'operator', 'value'
        );

        return $this;
    }

    public function find($id, $columns = ['*'])
    {
        return $this->where($this->primaryKey, '=', $id)->first($columns);
    }

    public function __call($method, $parameters)
    {
        return $this->$method(...$parameters);
    }

    public static function __callStatic($method, $parameters)
    {
        return (new static)->$method(...$parameters);
    }
}

class Article extends Model
{
    protected $primaryKey = 'id';

}
Article::find (1);


interface Milldeware {
    public static function handle(Closure $next);
}

class VerfiyCsrfToekn implements Milldeware {

    public static function handle(Closure $next)
    {
        echo '验证csrf Token <br>';
        $next();
    }
}

class VerfiyAuth implements Milldeware {

    public static function handle(Closure $next)
    {
        echo '验证是否登录 <br>';
        $next();
    }
}

class SetCookie implements Milldeware {
    public static function handle(Closure $next)
    {
        $next();
        echo '设置cookie信息！';
    }
}

$handle = function() {
    echo '当前要执行的程序!';
};

$pipe_arr = [
    'VerfiyCsrfToekn',
    'VerfiyAuth',
    'SetCookie',
];

$callback = array_reduce($pipe_arr,function($stack,$pipe) {
    return function() use($stack,$pipe){
        return $pipe::handle($stack);
    };
},$handle);

call_user_func($callback);

// 注意我们这里需要修改一下User的构造函数，如果不去修改。反射是不能动态创建接口的，那如果非要用接口该怎么处理呢？下一节我们讲Ioc容器的时候会去解决。


interface Log
{
    public function write();
}

// 文件记录日志
class FileLog implements Log
{
    public function write(){
        echo 'file log write...';
    }
}

// 数据库记录日志
class DatabaseLog implements Log
{
    public function write(){
        echo 'database log write...';
    }
}

class User
{
    protected $log;
    public function __construct(Log $log)
    {
        $this->log = $log;
    }
    public function login()
    {
        // 登录成功，记录登录日志
        echo 'login success...';
        $this->log->write();
    }
}

class Ioc
{
    public $binding = [];

    public function singleton($abstract, $concrete)
    {
        //这里为什么要返回一个closure呢？因为bind的时候还不需要创建User对象，所以采用closure等make的时候再创建FileLog;
        $this->binding[$abstract]['concrete'] = function ($ioc) use ($concrete) {
            return $ioc->build($concrete);
        };

    }

    public function make($abstract)
    {
        // 根据key获取binding的值
        $concrete = $this->binding[$abstract]['concrete'];
        return $concrete($this);
    }

    // 创建对象
    public function build($concrete) {
        $reflector = new ReflectionClass($concrete);
        $constructor = $reflector->getConstructor();
        if(is_null($constructor)) {
            return $reflector->newInstance();
        }else {
            $dependencies = $constructor->getParameters();
            $instances = $this->getDependencies($dependencies);
            return $reflector->newInstanceArgs($instances);
        }
    }

    // 获取参数的依赖
    protected function getDependencies($paramters) {
        $dependencies = [];
        foreach ($paramters as $paramter) {
            $dependencies[] = $this->make($paramter->getClass()->name);
        }
        return $dependencies;
    }
}

class UserFacade
{
    // 维护Ioc容器
    protected static $ioc;

    public static function setFacadeIoc($ioc)
    {
        static::$ioc = $ioc;
    }

    // 返回User在Ioc中的bind的key
    protected static function getFacadeAccessor()
    {
        return 'User';
    }

    // php 魔术方法，当静态方法被调用时会被触发
    public static function __callStatic($method, $args)
    {
        $instance = static::$ioc->make(static::getFacadeAccessor());
        return $instance->$method(...$args);
    }

}


//实例化IoC容器
$ioc = new Ioc();
$ioc->singleton('Log','FileLog');
$ioc->singleton('User','User');

UserFacade::setFacadeIoc($ioc);

UserFacade::login();
